package com.example.scribe.backend.handlers;

import com.example.scribe.SyntaxNode;
import com.example.scribe.backend.BytecodeOps;
import com.example.scribe.backend.ExpressionEmitter;
import com.example.scribe.backend.ExpressionNodeHandler;
import com.example.scribe.backend.LocalVariableAllocator;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.StackManipulation.Compound;

/**
 * Handler for unary expressions (!, -, ~).
 */
public final class UnaryExpressionHandler implements ExpressionNodeHandler {
    private final ExpressionEmitter exprEmitter;

    public UnaryExpressionHandler(ExpressionEmitter exprEmitter) {
        this.exprEmitter = exprEmitter;
    }

    @Override
    public boolean canHandle(String nodeType) {
        return "unary".equals(nodeType);
    }

    @Override
    public StackManipulation handle(SyntaxNode node, String generatedClassName, LocalVariableAllocator locals) {
        if (node == null || node.children().isEmpty()) {
            return StackManipulation.Trivial.INSTANCE;
        }

        // Unary structure: ('!' | '-' | '~') unary | call
        // Check if first child is an operator
        SyntaxNode firstChild = node.children().get(0);
        String op = null;
        
        // Check if first child is a Terminal with operator
        if (firstChild.type().startsWith("Terminal:")) {
            op = firstChild.text();
        } else if (firstChild.text() != null) {
            String text = firstChild.text();
            if ("!".equals(text) || "-".equals(text) || "~".equals(text)) {
                op = text;
            }
        }

        if (op != null && node.children().size() >= 2) {
            // Unary operator: emit the operand, then apply operator
            SyntaxNode operand = node.children().get(1);
            StackManipulation operandEmit = exprEmitter.emit(operand, generatedClassName, locals);
            
            if (operandEmit == StackManipulation.Trivial.INSTANCE) {
                return StackManipulation.Trivial.INSTANCE;
            }

            if ("~".equals(op)) {
                // Bitwise NOT: ~x = x XOR -1
                // Load operand, then load -1, then XOR
                return new Compound(operandEmit, BytecodeOps.pushInt(-1), BytecodeOps.ixor());
            } else if ("-".equals(op)) {
                // Negation: -x
                return new Compound(operandEmit, BytecodeOps.ineg());
            } else if ("!".equals(op)) {
                // Logical NOT: !x = (x == 0 ? 1 : 0)
                // For integers: if x == 0, return 1, else return 0
                // This is typically handled by comparison, but we can do it here too
                // For now, return trivial and let comparison handler deal with it
                return StackManipulation.Trivial.INSTANCE;
            }
        }

        // No unary operator, just emit the operand (call or primary)
        if (node.children().size() > 0) {
            SyntaxNode operand = node.children().get(0);
            return exprEmitter.emit(operand, generatedClassName, locals);
        }

        return StackManipulation.Trivial.INSTANCE;
    }
}

